package com.sharer.last.base.utils;

import cn.hutool.core.map.MapUtil;
import cn.hutool.core.util.ReflectUtil;

import org.springframework.cglib.beans.BeanMap;

import javax.xml.bind.JAXBContext;
import javax.xml.bind.Marshaller;
import javax.xml.bind.Unmarshaller;
import java.io.StringReader;
import java.io.StringWriter;
import java.lang.reflect.Field;
import java.lang.reflect.Modifier;
import java.math.BigDecimal;
import java.math.BigInteger;
import java.time.LocalDate;
import java.time.temporal.ChronoUnit;
import java.util.*;

/**
 * Object 类型转换相关
 */
public class ConvertUtil {



    /**
     * bean转map
     *
     * @param bean 原始bean
     * @param <T>  泛型
     * @return map
     */
    public static <T> Map<String, Object> beanToMap(T bean) {
        Map<String, Object> map = new HashMap<>();
        if (bean != null) {
            BeanMap beanMap = BeanMap.create(bean);
            for (Object key : beanMap.keySet()) {
                map.put(key + "", beanMap.get(key));
            }
        }
        return map;
    }

    /**
     * 将map装换为javabean对象
     *
     * @param map  原始map
     * @param bean 实例化空bean
     * @param <T>  泛型
     * @return 填充后的bean
     */
    public static <T> T mapToBean(Map<String, Object> map, T bean) {
        BeanMap beanMap = BeanMap.create(bean);
        beanMap.putAll(map);
        return bean;
    }

    /**
     * Map转换层Bean，使用泛型免去了类型转换的麻烦。
     *
     * @param <T>
     * @param map
     * @param beanClass
     * @return
     */
    public static <T> T map2Bean(Map<String, Object> map, Class<T> beanClass) {
        if (map == null) {
            return null;
        }
        T instance = null;
        try {
            instance = beanClass.newInstance();
            Field[] fields = instance.getClass().getDeclaredFields();
            for (Field field : fields) {
                int mod = field.getModifiers();
                if (Modifier.isStatic(mod) || Modifier.isFinal(mod)) {
                    continue;
                }
                field.setAccessible(true);
                field.set(instance, map.get(field.getName()));
            }
            return instance;
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }

    /**
     * 强转string,并去掉多余空格
     *
     * @param str          字符串
     * @param defaultValue 默认值
     * @return String
     */
    public static String toStr(Object str, String defaultValue) {
        if (null == str) {
            return defaultValue;
        }
        return String.valueOf(str);
    }

    /**
     * 强转string,并去掉多余空格
     *
     * @param str 字符串
     * @return String
     */
    public static String toStr(Object str) {
        return toStr(str, "");
    }

    /**
     * object转Integer
     *
     * @param object
     * @return
     */
    public static int toInt(Object object) {
        return toInt(object, 0);
    }

    public static int toInt(Object object, Integer defaultValue) {
        if (null == object) {
            return defaultValue;
        }
        try {
            return Integer.parseInt(object.toString());
        } catch (Exception e) {
            return defaultValue;
        }
    }
    /**
     * object转float
     */
    public static float toFloat(Object object) {
        return toFloat(object, 0f);
    }

    public static float toFloat(Object object, Float defaultValue) {
        if (null == object) {
            return defaultValue;
        }
        try {
            return Float.parseFloat(object.toString());
        } catch (Exception e) {
            return defaultValue;
        }
    }

    /**
     * object转Boolean
     *
     * @param object
     * @return
     */
    public static boolean toBoolean(Object object) {
        return toBoolean(object, false);
    }

    public static boolean toBoolean(Integer num) {
        if (num <= 0) {
            return false;
        } else {
            return true;
        }
    }

    public static boolean toBoolean(Object object, Boolean defaultValue) {
        if (null == object) {
            return defaultValue;
        }
        try {
            return Boolean.parseBoolean(object.toString());
        } catch (Exception e) {
            return defaultValue;
        }
    }

    public static BigDecimal toBigDecimal(Object value) {
        BigDecimal ret = null;
        if (value != null) {
            if (value instanceof BigDecimal) {
                ret = (BigDecimal) value;
            } else if (value instanceof String) {
                ret = new BigDecimal((String) value);
            } else if (value instanceof BigInteger) {
                ret = new BigDecimal((BigInteger) value);
            } else if (value instanceof Number) {
                ret = new BigDecimal(((Number) value).doubleValue());
            } else {
                //throw new ClassCastException("Not possible to coerce ["+value+"] from class "+value.getClass()+" into a BigDecimal.");
                ret = new BigDecimal(0);
            }
        }
        return ret;
    }

    /**
     * 根据clzz，value，将value转换成对应clzz类型的值，
     * 只限 基本类型
     *
     * @param value 需要转换的值
     * @param clzz
     * @author jianggm
     */
    public static Object convertToClass(String value, Class<?> clzz) {
        if (clzz.equals(String.class)) {
            return value;
        } else if (clzz.equals(int.class) || clzz.equals(short.class)) {
            return new Integer(value);
        } else if (clzz.equals(byte.class)) {
            return value.getBytes();
        } else if (clzz.equals(long.class)) {
            return new Long(value);
        } else if (clzz.equals(boolean.class) || clzz.equals(Boolean.class)) {
            return new Boolean(value);
        } else if (clzz.equals(float.class) || clzz.equals(Float.class)) {
            return new Float(value);
        } else if (clzz.equals(double.class) || clzz.equals(Double.class)) {
            return new Double(value);
        }
        return null;
    }

    /**
     * 转换枚举为对应的Map
     *
     * @param clazz     枚举类
     * @param fieldName 字段名
     * @return
     */
    public static Map<String, Object> enumToMap(Class<? extends Enum<?>> clazz, String... fieldName) {
        final Enum<?>[] enums = clazz.getEnumConstants();
        if (null == enums) {
            return null;
        }
        final Map<String, Object> map = MapUtil.newHashMap(enums.length);
        for (Enum<?> e : enums) {
            map.put(ReflectUtil.getFieldValue(e, fieldName[0]) + "", ReflectUtil.getFieldValue(e, fieldName[1]));
        }
        return map;
    }

    /**
     * 转换枚举为对应的Map
     */
    public static Map<String, Object> enumToMap(Class<? extends Enum<?>> clazz) {
        return enumToMap(clazz, "code", "title");
    }


    /**
     * xml转换成JavaBean
     *
     * @param xml xml格式字符串
     * @param t   待转化的对象
     * @return 转化后的对象
     * @throws Exception JAXBException
     */
    @SuppressWarnings({"unchecked"})
    public static <T> T convertToBean(String xml, Class<T> t) {
        try {
            T obj = null;
            JAXBContext context = JAXBContext.newInstance(t);
            Unmarshaller unmarshaller = context.createUnmarshaller();
            obj = (T) unmarshaller.unmarshal(new StringReader(xml));
            return obj;
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }

    /**
     * JavaBean转换成xml
     *
     * @param obj
     * @param encoding
     * @return
     */
    public static String convertToXml(Object obj, String encoding) {
        String result = null;
        try {
            JAXBContext context = JAXBContext.newInstance(obj.getClass());
            Marshaller marshaller = context.createMarshaller();
            marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true);
            marshaller.setProperty(Marshaller.JAXB_ENCODING, encoding);

            StringWriter writer = new StringWriter();
            marshaller.marshal(obj, writer);
            result = writer.toString();
        } catch (Exception e) {
            e.printStackTrace();
        }

        return result;
    }


    /***
     * 生日转年龄
     * @param birthday
     * @return
     */
    public static int birthdayToAge(LocalDate birthday) {
        int age = 0;
        if (birthday != null) {
            age = (int) birthday.until(LocalDate.now(), ChronoUnit.YEARS);
        }
        return age;
    }

    public static String[] listToArray(List<String> strList) {
        if (strList == null) {
            return new String[]{};
        }
        return strList.toArray(new String[strList.size()]);
    }

    public static List<String> arrayToList(String[] arr) {
        if (arr == null) {
            return new ArrayList<>();
        }
        return Arrays.asList(arr);
    }
}
